package com.wcj.study.multiredis.config;

import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * 自动注册redis类
 * 
 * @author 汪长军 Email：changjunwang@xinhe99.com
 * @date 2018-12-14 上午10:47:43
 * @copyright 信和上融网络科技(北京)有限公司
 */
class MultiRedisRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private ConversionService conversionService = new DefaultConversionService();

    private MultiRedisProperties properties;

    private static Map<String, JedisConnectionFactory> jedisConnectionFactoryMap;

    /**
     * TODO 添加方法说明
     *
     * @param importingClassMetadata
     * @param registry
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        if (this.properties != null && !this.properties.getInstance().isEmpty()) {
            MultiRedisConnectionFactory factory = new MultiRedisConnectionFactory(this.properties);
            try {
                MultiRedisRegister.jedisConnectionFactoryMap = factory.createRedisConnectionFactory();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }

            // RedisAutoConfiguration

            for (Entry<String, JedisConnectionFactory> obj : jedisConnectionFactoryMap.entrySet()) {
                JedisConnectionFactory jedisConnectionFactory = obj.getValue();
                String key = obj.getKey();

                String beanName = key + RedisConstants.DEFAULT_REDIS_KEY;
                registerRedisTemplate(registry, beanName, jedisConnectionFactory, RedisTemplate.class);

                beanName = key + RedisConstants.STRING_REDIS_KEY;
                registerRedisTemplate(registry, beanName, jedisConnectionFactory, StringRedisTemplate.class);

            }
        }
    }

    private void registerRedisTemplate(BeanDefinitionRegistry registry, String beanName,
        JedisConnectionFactory jedisConnectionFactory, Class<?> beanClass) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
        builder.addPropertyValue("connectionFactory", jedisConnectionFactory);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        registry.registerBeanDefinition(beanName, beanDefinition);
    }

    /**
     * 构造属性类
     *
     * @param environment
     */
    @Override
    public void setEnvironment(Environment environment) {

        MultiRedisProperties properties = new MultiRedisProperties();

        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment, "spring.redis.multi");

        Map<String, Object> propMap = propertyResolver.getSubProperties(".");

        RelaxedDataBinder dataBinder = new RelaxedDataBinder(properties);

        dataBinder.setConversionService(conversionService);
        dataBinder.setIgnoreNestedProperties(false);
        dataBinder.setIgnoreInvalidFields(false);
        dataBinder.setIgnoreUnknownFields(true);

        Map<String, Object> values = new HashMap<>(propMap);
        PropertyValues dataSourcePropertyValues = new MutablePropertyValues(values);
        dataBinder.bind(dataSourcePropertyValues);

        this.properties = properties;
    }

    /**
     * @return the jedisConnectionFactoryMap
     */
    public static Map<String, JedisConnectionFactory> getJedisConnectionFactoryMap() {
        return jedisConnectionFactoryMap;
    }

    /**
     * @param jedisConnectionFactoryMap the jedisConnectionFactoryMap to set
     */
    public static void setJedisConnectionFactoryMap(Map<String, JedisConnectionFactory> jedisConnectionFactoryMap) {
        MultiRedisRegister.jedisConnectionFactoryMap = jedisConnectionFactoryMap;
    }

}
